package cloud.seri.gateway.config.oauth2

import cloud.seri.gateway.security.oauth2.CookieTokenExtractor
import cloud.seri.gateway.security.oauth2.OAuth2AuthenticationService
import cloud.seri.gateway.security.oauth2.OAuth2CookieHelper
import cloud.seri.gateway.security.oauth2.OAuth2TokenEndpointClient
import cloud.seri.gateway.web.filter.RefreshTokenFilterConfigurer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer
import org.springframework.security.oauth2.provider.authentication.TokenExtractor
import org.springframework.security.oauth2.provider.token.TokenStore

/**
 * Configures the RefreshFilter refreshing expired OAuth2 token Cookies.
 */
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
class OAuth2AuthenticationConfiguration(
    private val oAuth2Properties: OAuth2Properties,
    private val tokenEndpointClient: OAuth2TokenEndpointClient,
    private val tokenStore: TokenStore
) : ResourceServerConfigurerAdapter()
{

    @Throws(Exception::class)
    override fun configure(http: HttpSecurity)
    {
        http
            .authorizeRequests()
            .antMatchers("/auth/login").permitAll()
            .antMatchers("/auth/logout").authenticated()
            .and()
            .apply(refreshTokenSecurityConfigurerAdapter())
    }

    /**
     * A `SecurityConfigurerAdapter` to install a servlet filter that refreshes OAuth2 tokens.
     */
    private fun refreshTokenSecurityConfigurerAdapter(): RefreshTokenFilterConfigurer
    {
        return RefreshTokenFilterConfigurer(uaaAuthenticationService(), tokenStore)
    }

    @Bean
    fun cookieHelper(): OAuth2CookieHelper
    {
        return OAuth2CookieHelper(oAuth2Properties)
    }

    @Bean
    fun uaaAuthenticationService(): OAuth2AuthenticationService
    {
        return OAuth2AuthenticationService(tokenEndpointClient, cookieHelper())
    }

    /**
     * Configure the ResourceServer security by installing a new [TokenExtractor].
     */
    @Throws(Exception::class)
    override fun configure(resources: ResourceServerSecurityConfigurer)
    {
        resources.tokenExtractor(tokenExtractor())
    }

    /**
     * The new [TokenExtractor] can extract tokens from Cookies and Authorization headers.
     *
     * @return the [CookieTokenExtractor] bean.
     */
    @Bean
    fun tokenExtractor(): TokenExtractor
    {
        return CookieTokenExtractor()
    }

}
